//读取AD值并转换成F温度值,得出 烤炉温度,肉探针1温度,肉探针2温度
//ESP32 ADC:
//ADC驱动程序API支持ADC1（9个通道，连接到GPIO 32-39）和ADC2（10个通道，连接到GPIO 0,2,4,12-15和25-27）
//应用程序使用ADC2有一些限制：
//只有当Wi-Fi未启动时，应用程序才可以使用ADC2，因为ADC也被较高优先级的Wi-Fi驱动器使用。
//某些ADC2引脚用作固定用途（GPIO 0,2,15），因此不能自由使用

#include "../main.h"
#include "Tool.h"
#include "TempADC.h"
#include "../aws_esp32/aws_iot_Publish.h"

#define filter_fun 1

#ifdef filter_fun
uint8_t Calbr_Temp_Flag=0;
uint8_t Change_Mode_Flag=0;
uint8_t Unit_Change = 0;
#endif
uint16_t temp_con_state =0;

#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate

_RTD RTD[4]; //0:Vref, 1: RTD, 2: Probe1, 3:Probe2
uint8_t RTD1_status, RTD1_cnt = 0, RTD_cnt = 0;
uint16_t OvenTemp_RTD_C = 100;
uint16_t OvenTemp_PROBE_C = 100;
uint8_t Temperature_sign = 0;

uint8_t LowTemp_Ctrl = 0; //1:重置低温检测过程, 0:继续执行低温检测

esp_adc_cal_characteristics_t *adc_chars;
_Temp_Param Temp_Param;
TempDetection_S TempDetection;

#ifdef Debug_ADC
uint16_t Debug_Seq = 0;
uint32_t DebugAdc[11];
#endif


void TempADC_Output(void)
{
    if(RTD[RTD_Seq_RTD].status == Pt_Open)
    {
        if(Temp_Param.oven_Err == Pt_Normal) Temp_Param.oven_Err = Pt_Open; //确保只能出现一种Er报警错误显示
    }
    else if(RTD[RTD_Seq_RTD].status == Pt_Short)
    {
        if(Temp_Param.oven_Err == Pt_Normal) Temp_Param.oven_Err = Pt_Short;
    }
    else if(RTD[RTD_Seq_RTD].status == Pt_LowTemp)
    {
        if(Temp_Param.oven_Err == Pt_Normal) Temp_Param.oven_Err = Pt_LowTemp;
    }
    else if(RTD[RTD_Seq_RTD].status == Pt_HighTemp)
    {
        if(Temp_Param.oven_Err == Pt_Normal) Temp_Param.oven_Err = Pt_HighTemp;
    }

//A通道
    if (RTD[RTD_Seq_Probe1].status == Pt_Normal)
    { 
        if(Temp_Param.probe1_Err == Pt_Open) Buzzer_Encoder_Down(); //检测到插入肉探针
        Temp_Param.probe1_Err = Pt_Normal;
        Temp_Param.probe1 = RTD[RTD_Seq_Probe1].value;
        UI_System.ProbeA.Actual = Temp_Param.probe1;
        // UI_ProbeA_Temp_Setting.v_detect = Probe_Valid;
    }
    else if(RTD[RTD_Seq_Probe1].status == Pt_Short)
    {
        Temp_Param.probe1_Err = Pt_Short;
        // UI_ProbeA_Temp_Setting.v_detect = Probe_NotValid;
    }
    else if(RTD[RTD_Seq_Probe1].status == Pt_Open)
    {
        if(Temp_Param.probe1_Err == Pt_Normal)
        {
            Buzzer_Encoder_Down(); //检测到拔出肉探针
            UI_System.ProbeA.Settings = Alarm_Probe_Min;
            UI_System.Alarm_ProbeA = Alarm_None; 
        }
        Temp_Param.probe1_Err = Pt_Open;
        // UI_ProbeA_Temp_Setting.v_detect = Probe_NotValid;
    }

//B通道
    if (RTD[RTD_Seq_Probe2].status == Pt_Normal)
    { 
        if(Temp_Param.probe2_Err == Pt_Open) Buzzer_Encoder_Down(); //检测到拔出肉探针
        Temp_Param.probe2_Err = Pt_Normal;
        Temp_Param.probe2 = RTD[RTD_Seq_Probe2].value;
        UI_System.ProbeB.Actual = Temp_Param.probe2;
    }
    else if(RTD[RTD_Seq_Probe2].status == Pt_Short)
    {
        Temp_Param.probe2_Err = Pt_Short;
        // UI_ProbeB_Temp_Setting.v_detect = Probe_NotValid;
    }
    else if(RTD[RTD_Seq_Probe2].status == Pt_Open)
    {
        if(Temp_Param.probe2_Err == Pt_Normal)
        {
            Buzzer_Encoder_Down(); //检测到拔出肉探针
            UI_System.ProbeB.Settings = Alarm_Probe_Min;
            UI_System.Alarm_ProbeB = Alarm_None;
        }
        Temp_Param.probe2_Err = Pt_Open;
        // UI_ProbeB_Temp_Setting.v_detect = Probe_NotValid;
    }
}

//单次采样指定通道
uint32_t ADC_Read(uint8_t channel)
{
    uint32_t voltage = 0;

    esp_adc_cal_get_voltage(channel,adc_chars,&voltage);
    
    return voltage;
}

uint32_t Kalman_Filter(uint32_t last,uint32_t z_measure)
{
    static float x_last=0;   
	static float p_last=0.02;
	float Q=0.018;
	float R=0.542;
	float kg;
	float x_mid;
	float x_now;
	float p_mid;
	float p_now;

	x_last= last;
	x_mid=x_last;
    
    x_mid = x_last;    //x_last=x(k-1|k-1),x_mid=x(k|k-1)
    p_mid = p_last+Q;  //p_mid=p(k|k-1),p_last=p(k-1|k-1),Q=噪声
    kg=p_mid/(p_mid+R); //kg为kalman filter，R为噪声
    
    x_now=x_mid+kg*(z_measure-x_mid);//估计出的最优值

    // printf("测量值: %d\n",z_measure);  //显示测量值以及真值与测量值之间的误差
    // printf("卡尔曼滤波值: %f\n\n",x_now);  //显示kalman估计值以及真值和卡尔曼估计值的误差

    p_now=(1-kg)*p_mid;//最优值对应的covariance
    p_last = p_now;  //更新covariance值
    x_last = x_now;  //更新系统状态值

    return (uint32_t)x_now;
}

//中位值平均滤波算法, 支持10个数据滤波
//Fiter(0,10): 能返回滤波结果
//除了滤波,采样的数据也不能是同一个点,否则滤波的数据都来自同一个点,滤波也就没意义
uint32_t Filter(uint32_t ch, uint32_t temp)
{
    static uint32_t data[4][10];
    static uint32_t dataSeq = 0;
    uint32_t i = 0;
    static uint32_t total[4],total_pre[4];
    uint32_t sum = 0;

    if(ch >= RTD_Seq_End) return;
    if(temp != 0xffffffff)
    {
        data[ch][dataSeq] = temp;
        if(dataSeq < 9) dataSeq++;
    }
    else
    {
        for(i = 0; i < dataSeq; i++)
        {
            sum += data[ch][i];
        }
        if(dataSeq > 0)
        {
            total[ch] = sum / dataSeq;
            dataSeq = 0;
        }
        if((total[ch] > (total_pre[ch] + 50)) || ((total[ch] + 50) < total_pre[ch])) total_pre[ch] = total[ch]; //超出绝对值范围,加快滤波
        for(i = 0; i < 250; i++)
        {
            total[ch] = Kalman_Filter(total_pre[ch],total[ch]);
            total_pre[ch] = total[ch];
        }
    }
    return total[ch];
}

void ADC_KeyUpDown(void)
{
    #ifdef filter_fun				   
        Calbr_Temp_Flag = 0;
        Change_Mode_Flag = 1;
    #endif
}
void ADC_Filter(void)
{
    #ifdef filter_fun				   
        Calbr_Temp_Flag = 0;
        Change_Mode_Flag = 0;
        Unit_Change = 10;
    #endif
}
void ADSampling(void)
{
    static uint16_t seq = 0;
    uint32_t temp = 0;
    double temp_Double = 0;
    static uint8_t ch = 0;


    if (seq < 10)
    { //读取AD采样值
        if(ch == RTD_Seq_Vref) temp = ADC_Read(ADC_Channel_Vref);
        else if(ch == RTD_Seq_RTD) temp = ADC_Read(ADC_Channel_Oven);
        else if(ch == RTD_Seq_Probe1) temp = ADC_Read(ADC_Channel_Meat1);
        else if(ch == RTD_Seq_Probe2) temp = ADC_Read(ADC_Channel_Meat2);
        Filter(ch,temp);
        seq++;
    }
    else
    {
        temp = Filter(ch,0xffffffff);
        if(ch == RTD_Seq_Vref)
        {
            RTD[RTD_Seq_Vref].value = temp; //Vref
        }
        else
        {
            temp_Double = V_Convert_R(RTD[RTD_Seq_Vref].value,temp); //1702 1674是1/2 VDD的采样值
            temp_Double = Quadratic_FC(temp_Double);
            if(Pt1000_State == Pt1000_Short) RTD[ch].status = Pt_Short;
            else if(Pt1000_State == Pt1000_Open) RTD[ch].status = Pt_Open;
            else if(ch != RTD_Seq_RTD)
            {
                RTD[ch].status = Pt_Normal;
            }
            if(temp_Double > 999) temp_Double = 999; //999 ℉
            RTD[ch].value = temp_Double;

    #ifdef filter_fun
            if ((Calbr_Temp_Flag == 0) && (Change_Mode_Flag == 0))
            {
                if ((RTD[RTD_Seq_RTD].value <= (temp_set + 10)) && (RTD[RTD_Seq_RTD].value >= (temp_set - 10)))
                {
                    Calbr_Temp_Flag = 1;
                }
                if(Unit_Change > 0)
                {
                    Unit_Change--;
                    Calbr_Temp_Flag = 0;
                }
                UI_System.RTD.Actual = RTD[RTD_Seq_RTD].value;
            }
            if (Change_Mode_Flag == 1)
            {
                temp_con_state++;
                if (temp_con_state >= 20)
                {
                    temp_con_state -= 20;
                    if ((UI_System.RTD.Actual > (RTD[RTD_Seq_RTD].value + 5)) || ((UI_System.RTD.Actual + 5) < RTD[RTD_Seq_RTD].value))
                    {
                        // Ovenprobetemp = Ovenprobetemp - (Ovenprobetemp >> 4) + (RTD[RTD_Seq_RTD].value >> 4);
                        UI_System.RTD.Actual = UI_System.RTD.Actual - (UI_System.RTD.Actual >> 4) + (RTD[RTD_Seq_RTD].value >> 4);
                    }
                    else
                    {
                        temp_con_state = 0;
                        Change_Mode_Flag = 0;
                    }
                }
            }
            if (Calbr_Temp_Flag == 1)
            {
                UI_System.RTD.Actual = (temp_set + RTD[RTD_Seq_RTD].value) / 2;
            }
    #else					 
            UI_System.RTD.Actual = RTD[RTD_Seq_RTD].value;
    #endif
            TempADC_Output();
        }

        ch++;
        if (ch >= RTD_Seq_End) ch = 0;
        seq = 0;
    }
}

//高温报警: 烤炉温度长时间>550°F,Tick 1s
void HighTempAlarm(void)
{
    static uint16_t HighTemp_Count = 0;

    if (RTD[RTD_Seq_RTD].value > GetTemp(550))
    {
        if (HighTemp_Count >= 10)
        { //持续10s,执行高温报警
            if(RTD[RTD_Seq_RTD].status == Pt_Normal) RTD[RTD_Seq_RTD].status = Pt_HighTemp;
        }
        else HighTemp_Count++;
    }
    else HighTemp_Count = 0;
}

//Tick 1s
//低温报警检测原理: 低于120,持续30min,触发低温报警
void LowTempAlarm(void)
{
    static uint16_t LowTemp_Count = 0;
    static uint16_t LowTemp_Is = 0;

    if((UI_System.Grill_state < State_Grill_Ignite) || (UI_System.Grill_state == State_Grill_Misfire))
    { //点火后,开始检测低温,高温报警, 熄火后禁止
        LowTemp_Count = 0;
        return; 
    }

    if (RTD[RTD_Seq_RTD].value < GetTemp(120))
    {
        LowTemp_Is = 0;
        if(LowTemp_Count < 1800) LowTemp_Count++;
        if(LowTemp_Count >=  1800)
        {
            if(RTD[RTD_Seq_RTD].status == Pt_Normal) RTD[RTD_Seq_RTD].status = Pt_LowTemp; //RTD 低温报警,会触发自动停止温控
        }
    }
    else
    {
        LowTemp_Is++;
        if(LowTemp_Is >= 10)
        {
            LowTemp_Is = 0;
            if(LowTemp_Count > 0) LowTemp_Count = 0;
        }
    }
    HighTempAlarm();
}

void AD_IOConfig(void)
{
    gpio_config_t io_conf;

    //disable interrupt
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_INPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = AD_GPIO_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);  
    // gpio_set_level(IO_Oven,1);
    // gpio_set_level(IO_Probe1,1);
    // gpio_set_level(IO_Probe2,1);
    // gpio_set_level(IO_Vref,1);
}

//Reference voltage: VDD
void ADInit(void)
{
    uint16_t i;

    AD_IOConfig();
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(ADC_Channel_Oven, ADC_ATTEN_DB_11);
    //Characterize ADC
    adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
    esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars); //参考电压: 3300mV

    RTD[RTD_Seq_RTD].value = 75;
    RTD[RTD_Seq_RTD].status = Pt_Normal;
    Temp_Param.probe1_Err = Pt_Open;
    Temp_Param.probe2_Err = Pt_Open;

    for(i = 0; i < 30*3; i++)
    {
        ADSampling(); //防止开机肉探针报警
    }
}


//Tick 1s
void ADC_Clock(void)
{
    static uint8_t count10s = 0;
    int32_t temp;

    LowTempAlarm();
    
    if((RTD[RTD_Seq_Probe1].status == Pt_Short) || (RTD[RTD_Seq_Probe2].status == Pt_Short))
    {
        if(count10s < 0xff) count10s++;
        if(count10s >= 10)
        {
            count10s = 0;
        }
    }
    else
    {
        if(count10s > 0) count10s = 0;
    }
}
//Tick 2ms
void ADC_Clock_2ms(void)
{
    static uint16_t temp_12ms = 0;
    static uint16_t temp_1s = 0;

    temp_12ms++;
    if(temp_12ms >= 6)
    {
        temp_12ms = 0;
        ADSampling();
    }
    temp_1s++;
    if(temp_1s >= 500)
    {
        temp_1s = 0;
        ADC_Clock();
    }
}
